﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Threading;
using EbbinghausWord.Common;
using EbbinghausWord.DAL;
using EbbinghausWord.Entities;

namespace EbbinghausWord.BLL
{
    /// <summary>
    /// 发音管理
    /// </summary>
    public class VoiceManager
    {
        #region private field
        private static readonly IsolatedStorageFile _solatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication();
        #endregion

        #region private method

        /// <summary>
        /// 发送获得单词发音的事件
        /// </summary>
        /// <param name="english"></param>
        private void OnGetVoice(string english)
        {
            if (GetVoiceCompleted != null)
            {
                //把声音文件从数据库中取出来，放在磁盘上
                using (var fs = _solatedStorageFile.OpenFile("voice.mp3", FileMode.Create))
                {
                    var voice = new VoiceDAL().GetVoiceStream(english);

                    fs.Write(voice, 0, voice.Length);

                    GetVoiceCompleted(this, new VoiceEventArgs()
                    {
                        VoiceFileStream = fs,
                    });
                }
            }
        }

        /// <summary>
        /// 发送获取发音失败的事件
        /// </summary>
        /// <param name="errorWord"></param>
        private void OnGetVoiceFailed(string errorWord)
        {
            if (GetVoiceFailed != null)
            {
                GetVoiceFailed(this, new VoiceFailedEventArgs() { ErrorWord = errorWord });
            }
        }

        private void ClientOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            var english = e.UserState.ToString();

            try
            {
                var byData = new byte[e.Result.Length];
                e.Result.Read(byData, 0, (int)e.Result.Length);

                //在数据库中保存声音文件
                new VoiceDAL().AddVoice(new TableVoiceEntity() { English = english, Voice = byData });

                OnGetVoice(english);
            }
            catch (Exception ex)
            {
                OnGetVoiceFailed(english);
            }
        }

        #endregion

        #region public method

        /// <summary>
        /// 异步获得单词发音
        /// </summary>
        /// <param name="english"></param>
        /// <param name="isCheckExist">是否检查声音存在</param>
        public void GetVoiceAsync(string english, bool isCheckExist = true)
        {
            //文件是否存在，如果存在，则返回文件流
            if ((isCheckExist) && (IsVoiceExist(english)))
            {
                OnGetVoice(english);
            }
            else
            {
                try
                {
                    //通知外边，需要下载，调用者可能会显示下载进度条
                    if (VoiceDownloading != null)
                    {
                        VoiceDownloading(this, null);
                    }

                    //如果音乐文件不存在，则下载
                    var client = new WebClient();
                    client.OpenReadCompleted += ClientOpenReadCompleted;
                    client.OpenReadAsync(new Uri("http://dict.youdao.com/dictvoice?audio=" + english,
                        UriKind.Absolute), english);
                }
                catch (Exception ex)
                {
                    OnGetVoiceFailed(english);
                }
            }
        }

        /// <summary>
        /// 声音文件是否存在
        /// </summary>
        /// <param name="english"></param>
        /// <returns></returns>
        public static bool IsVoiceExist(string english)
        {
            return new VoiceDAL().IsVoiceExist(english);
        }

        /// <summary>
        /// 删除指定单词的发音文件
        /// </summary>
        /// <param name="english"></param>
        public static void DeleteVoiceFile(string english)
        {
            if (IsVoiceExist(english))
            {
                new VoiceDAL().DeleteVoice(english);
            }
        }

        /// <summary>
        /// 获得根据书籍，获得声音文件下载的信息
        /// </summary>
        /// <returns></returns>
        public static List<BookVoiceEntity> GetAllBookVoiceInfo()
        {
            //获得所有书籍
            var books = BookDAL.GetAllBook();

            //获得书籍对应的所有词典列表
            var bookWord = BookDAL.GetAllBookWords();

            //获得已经下载的声音文件列表
            var hasDownloadWord = new VoiceDAL().GetAllDownloadedEnglish()
                .Join(bookWord, x => x, x => x.English,
                      (x, y) => y).ToList();

            //单词总数统计
            return books.GroupJoin(bookWord, x => x.BookId, x => x.BookId,
                                   (x, y) => new
                                   {
                                       Book = x,
                                       BookWordCount = y.Count()
                                   })
                //已经下载的统计
                .GroupJoin(hasDownloadWord, x => x.Book.BookId, x => x.BookId,
                           (x, y) => new BookVoiceEntity()
                           {
                               BookId = x.Book.BookId,
                               BookName = x.Book.BookName,
                               HasDownloadWordCount = y.Count(),
                               TotalWordCount = x.BookWordCount,
                           }).Where(x => x.TotalWordCount != 0).ToList();
        }
        #endregion

        #region event

        /// <summary>
        /// 获取单词发音完成
        /// </summary>
        public event EventHandler<VoiceEventArgs> GetVoiceCompleted;

        /// <summary>
        /// 下载单词发音失败
        /// </summary>
        public event EventHandler<VoiceFailedEventArgs> GetVoiceFailed;

        /// <summary>
        /// 准备开始下载单词发音文件
        /// </summary>
        public event EventHandler<VoiceFailedEventArgs> VoiceDownloading;

        #endregion

        #region 多文件下载

        private static int _downloadIndex = 0;
        private bool _isBreakDownload = false;

        /// <summary>
        /// 根据书籍Id下载单词发音
        /// </summary>
        private void DownloadVoice(int bookId)
        {
            var voiceManager = new VoiceManager();
            var resetEvent = new AutoResetEvent(false);
            var currentWordIndex = 0;
            var totalWordCount = new BookDAL().GetBookWordCountByBookId(bookId);

            voiceManager.GetVoiceCompleted += (s, ex) =>
                                                  {
                                                      //通知下载进度变更
                                                      if (MuliDownloadPercentaging != null)
                                                      {
                                                          MuliDownloadPercentaging(null, new MuliDownloadPercentageEventArgs()
                                                                                             {
                                                                                                 HaveDownloadCount = currentWordIndex,
                                                                                                 TotalCount = totalWordCount,
                                                                                             });
                                                      }

                                                      //通知事件放行
                                                      resetEvent.Set();
                                                  };

            //获得需要下载的文件
            var wordList = new VoiceDAL().GetEnglishForDownloadByBookId(bookId);

            //开始下载
            currentWordIndex = totalWordCount - wordList.Count;
            foreach (var english in wordList)
            {
                if (++currentWordIndex == totalWordCount)
                {

                }

                //用户是否停止下载
                if (_isBreakDownload)
                {
                    return;
                }

                //下载文件，无需检查，因为将要下载的文件肯定不存在
                voiceManager.GetVoiceAsync(english, false);
                resetEvent.WaitOne(5000);
            }

            //抛出下载完成的事件
            if (MultiDownloadVoiceCompleted != null)
            {
                MultiDownloadVoiceCompleted(this, null);
            }
        }

        /// <summary>
        /// 根据书籍Id下载发音文件
        /// </summary>
        /// <param name="bookId"></param>
        public void StartDownloadVoice(int bookId)
        {
            _isBreakDownload = false;
            _downloadIndex = 0;
            new Thread(() => DownloadVoice(bookId)).Start();
        }

        /// <summary>
        /// 停止下载发音文件
        /// </summary>
        public void StopDownloadVoice()
        {
            _isBreakDownload = true;
        }

        /// <summary>
        /// 多文件下载的下载进度
        /// </summary>
        public event EventHandler<MuliDownloadPercentageEventArgs> MuliDownloadPercentaging;

        /// <summary>
        /// 多文件下载的事件
        /// </summary>
        public event EventHandler<EventArgs> MultiDownloadVoiceCompleted;

        /// <summary>
        /// 取消单词发音下载
        /// </summary>
        public event EventHandler<EventArgs> CancelVoiceCompleted;

        #endregion
    }

    /// <summary>
    /// 单词发音的事件参数类
    /// </summary>
    public class VoiceEventArgs : EventArgs
    {
        public Stream VoiceFileStream { get; set; }
    }


    /// <summary>
    /// 单词发音 获取失败的 事件类
    /// </summary>
    public class VoiceFailedEventArgs : EventArgs
    {
        public string ErrorWord { get; set; }
    }


    /// <summary>
    /// 多文件下载的参数
    /// </summary>
    public class MuliDownloadPercentageEventArgs : EventArgs
    {
        /// <summary>
        /// 已经下载的文件数量
        /// </summary>
        public int HaveDownloadCount { get; set; }

        /// <summary>
        /// 总共需要下载的文件数量
        /// </summary>
        public int TotalCount { get; set; }
    }
}
